package com.finalterm.payment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.finalterm.common.constant.Constants;
import com.finalterm.common.exception.BusinessException;
import com.finalterm.common.result.Result;
import com.finalterm.order.vo.OrderVO;
import com.finalterm.payment.dto.PaymentExecuteDTO;
import com.finalterm.payment.entity.Payment;
import com.finalterm.payment.feign.OrderServiceClient;
import com.finalterm.payment.mapper.PaymentMapper;
import com.finalterm.payment.service.PaymentService;
import com.finalterm.payment.service.PaymentTimeoutService;
import com.finalterm.payment.vo.PaymentVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 支付服务实现
 */
@Slf4j
@Service
@RefreshScope
public class PaymentServiceImpl implements PaymentService {
    
    @Autowired
    private PaymentMapper paymentMapper;

    @Autowired
    private OrderServiceClient orderServiceClient;

    @Autowired
    private PaymentTimeoutService paymentTimeoutService;

    @Value("${payment.timeout:300}")
    private Integer paymentTimeout;
    
    private static final Map<Integer, String> PAYMENT_METHOD_MAP;
    private static final Map<Integer, String> STATUS_MAP;

    static {
        Map<Integer, String> paymentMethodMap = new HashMap<>();
        paymentMethodMap.put(1, "支付宝");
        paymentMethodMap.put(2, "微信支付");
        paymentMethodMap.put(3, "银行卡");
        PAYMENT_METHOD_MAP = Collections.unmodifiableMap(paymentMethodMap);

        Map<Integer, String> statusMap = new HashMap<>();
        statusMap.put(0, "待支付");
        statusMap.put(1, "支付成功");
        statusMap.put(2, "支付失败");
        statusMap.put(3, "已退款");
        STATUS_MAP = Collections.unmodifiableMap(statusMap);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentVO executePayment(Long userId, PaymentExecuteDTO executeDTO) {
        // 1. 验证订单信息
        Result<OrderVO> orderResult = orderServiceClient.getOrderByOrderNo(executeDTO.getOrderNo());
        if (orderResult.getCode() != 200 || orderResult.getData() == null) {
            log.error("订单信息获取失败，订单号：{}", executeDTO.getOrderNo());
            throw new BusinessException("订单信息获取失败");
        }
        
        // 2. 检查是否已经支付
        Payment existPayment = getPaymentByOrderNoFromDB(executeDTO.getOrderNo());
        if (existPayment != null && existPayment.getStatus() == 1) {
            log.error("订单已支付，请勿重复支付，订单号：{}", executeDTO.getOrderNo());
            throw new BusinessException("订单已支付，请勿重复支付");
        }
        
        // 3. 生成支付单号
        String paymentNo = generatePaymentNo();
        
        // 4. 模拟支付处理
        boolean paymentSuccess = simulatePayment(executeDTO);
        
        // 5. 创建支付记录
        Payment payment = new Payment();
        payment.setPaymentNo(paymentNo);
        payment.setOrderNo(executeDTO.getOrderNo());
        payment.setUserId(userId);
        payment.setAmount(executeDTO.getAmount());
        payment.setPaymentMethod(executeDTO.getPaymentMethod());
        payment.setStatus(paymentSuccess ? 1 : 2);
        payment.setThirdPartyTransactionId(generateThirdPartyTransactionId());
        payment.setPaymentTime(paymentSuccess ? LocalDateTime.now() : null);
        payment.setCreateTime(LocalDateTime.now());
        payment.setUpdateTime(LocalDateTime.now());
        payment.setRemark(paymentSuccess ? "支付成功" : "支付失败");

        log.info("落庫開始");
        paymentMapper.insert(payment);
        
        // 6. 如果支付成功，更新订单状态
        if (paymentSuccess) {
            try {
                Result<Boolean> updateResult = orderServiceClient.updatePaymentStatus(executeDTO.getOrderNo());
                if (updateResult.getCode() != 200 || updateResult.getData() == null || !updateResult.getData()) {
                    log.warn("订单状态更新失败，订单号：{}", executeDTO.getOrderNo());
                }
            } catch (Exception e) {
                log.error("订单状态更新异常：{}", e.getMessage());
            }
        }
        
        // 7. 转换为VO返回
        PaymentVO paymentVO = convertToVO(payment);
        
        log.info("支付处理完成，支付单号：{}，结果：{}", paymentNo, paymentSuccess ? "成功" : "失败");
        return paymentVO;
    }
    
    @Override
    public PaymentVO getPaymentByOrderNo(String orderNo) {
        Payment payment = getPaymentByOrderNoFromDB(orderNo);
        if (payment == null) {
            throw new BusinessException("支付记录不存在");
        }
        return convertToVO(payment);
    }
    
    @Override
    public List<PaymentVO> getUserPayments(Long userId) {
        LambdaQueryWrapper<Payment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Payment::getUserId, userId)
                .orderByDesc(Payment::getCreateTime);
        
        List<Payment> payments = paymentMapper.selectList(wrapper);
        return payments.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handlePaymentCallback(String paymentNo, String thirdPartyTransactionId, Integer status) {
        LambdaQueryWrapper<Payment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Payment::getPaymentNo, paymentNo);
        Payment payment = paymentMapper.selectOne(wrapper);
        
        if (payment == null) {
            log.warn("支付回调处理失败，支付记录不存在，支付单号：{}", paymentNo);
            return false;
        }
        
        // 更新支付状态
        payment.setStatus(status);
        payment.setThirdPartyTransactionId(thirdPartyTransactionId);
        payment.setPaymentTime(status == 1 ? LocalDateTime.now() : null);
        payment.setUpdateTime(LocalDateTime.now());
        
        paymentMapper.updateById(payment);
        
        // 如果支付成功，更新订单状态
        if (status == 1) {
            try {
                orderServiceClient.updatePaymentStatus(payment.getOrderNo());
            } catch (Exception e) {
                log.error("支付回调更新订单状态失败：{}", e.getMessage());
            }
        }
        
        log.info("支付回调处理完成，支付单号：{}，状态：{}", paymentNo, status);
        return true;
    }
    
    /**
     * 从数据库获取支付记录
     */
    private Payment getPaymentByOrderNoFromDB(String orderNo) {
        LambdaQueryWrapper<Payment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Payment::getOrderNo, orderNo);
        return paymentMapper.selectOne(wrapper);
    }
    
    /**
     * 生成支付单号
     */
    private String generatePaymentNo() {
        return "PAY" + System.currentTimeMillis() + String.format("%04d", new Random().nextInt(10000));
    }
    
    /**
     * 生成第三方交易流水号
     */
    private String generateThirdPartyTransactionId() {
        return "TXN" + System.currentTimeMillis() + String.format("%06d", new Random().nextInt(1000000));
    }
    
    /**
     * 模拟支付处理
     */
    private boolean simulatePayment(PaymentExecuteDTO executeDTO) {
        long startTime = System.currentTimeMillis();

        try {
            // 获取当前支付超时配置
            Integer currentTimeout = paymentTimeoutService.getPaymentTimeout();
            log.info("开始支付处理，当前超时配置: {}秒", currentTimeout);

            // 模拟支付处理时间（随机1-3秒）
            int processingTime = 1000 + new Random().nextInt(2000);
            Thread.sleep(processingTime);

            // 检查是否超时
            if (paymentTimeoutService.isPaymentTimeout(startTime)) {
                return false;
            }

            // 模拟支付成功率90%
            boolean success = new Random().nextInt(100) < 90;

            // 记录支付处理时间
            paymentTimeoutService.logPaymentDuration(startTime, success);

            return success;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("支付处理被中断");
            paymentTimeoutService.logPaymentDuration(startTime, false);
            return false;
        }
    }
    
    /**
     * 转换为VO
     */
    private PaymentVO convertToVO(Payment payment) {
        PaymentVO vo = new PaymentVO();
        BeanUtils.copyProperties(payment, vo);
        vo.setPaymentMethodName(PAYMENT_METHOD_MAP.get(payment.getPaymentMethod()));
        vo.setStatusName(STATUS_MAP.get(payment.getStatus()));
        return vo;
    }
}
